﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using TransportLayer;
namespace TransportLayer.NodeLibrary
{
    //generyczne źródło ruchu, wysyłające przez swój port dane o losowej długości 
    public class Source : Cleaner
    {
        private int id;
        public int Id { get { return id; } }

        private string name;
        public string Name { get { return name; } set { name = value; } }

        private Log log;
        public Log Log { get { return log; } }

        private SourceSNP snp;
        public SourceSNP Snp { get { return snp; } }

        private string message = "";
        public string Message { get { return message; } set { message = value; } }

        private Dictionary<int, PduStream> targets = new Dictionary<int, PduStream>();
        public Dictionary<int, PduStream> Targets { get { return targets; } }

        private Dictionary<int, CTP> matrix = new Dictionary<int, CTP>();
        public Dictionary<int, CTP> Matrix { get { return matrix; } }

        private int speed;
        public int Speed { set { speed = value;  } }

        private PortOut portOut; 
        public PortOut PortOut { get { return portOut; } }

        private int Rand { get { return rand.Next() % 100; } }
        private Random rand;

        public int PositionX;
        public int PositionY;


        public int CallerListeningPort { get; set; }

        public Source(TransportLayer.Node node, int managerPort)
        {
            PositionX = node.PositionX;
            PositionY = node.PositionY;
            this.id = node.Id;
            this.name = (string)node.Name.Clone();
            this.log = new Log("Log zrodla " + Name);
            this.snp = new SourceSNP(this, managerPort);
            this.portOut = new PortOut(0);
            this.rand = new Random();
        }

        private int maximumlength = 1000;
        public void SetMaximumLength(int len) { maximumlength = len; } //Ustawianie maxymalnej dlugosci generowanego strumieni uzytkowego
        public int GetMaximumLength() { return maximumlength; } //Zwracanie maxymalnej dlugosci generowanego strumieni uzytkowego


        public void GenerateData(int trg, string mess)
        {
            try
            {
                CTP target = Matrix[trg];

                var pu = new Frame();
                pu.Stream = target.Stream;
                pu.Put = ProtocolUnitType.NORMAL_PACKET;
                pu.PduMessage = mess;
                this.portOut.Send(pu);
                log.LogMsg("Send packet: " + target.Stream + ":0");

            }
            catch (KeyNotFoundException) { }
        }

        public void Send(PduStream trg)
        {
            try
            {
                if (trg.Capacity == 0)
                    this.GenerateData(trg.Target, trg.Message);
                else
                {
                    while (trg.Capacity != 0)
                    {
                        this.GenerateData(trg.Target, trg.Message);
                        Thread.Sleep(1000/trg.Capacity);
                    }
                }
            }
            catch (Exception) { }
        }

        public bool Add(int port, int connectionID)
        {
            if (matrix.ContainsKey(connectionID))
                matrix.Remove(connectionID);
           
                CTP re = new CTP(Rand, port);


                while (Matrix.ContainsValue(re))
                { re = new CTP(Rand, port); }
                matrix.Add(connectionID, re);
                portOut.Send(ConfigProtocolUnit(re.Stream, connectionID));
                return true;
        }

        private Frame ConfigProtocolUnit(int rand, int connectionID)
        {
            Frame pu = new Frame();
            pu.Put = ProtocolUnitType.CONF_PACKET;
            pu.PduMessage = "" + rand + " " + connectionID;

            return pu;
        }

        public void Clean()
        {
            portOut.Clean();
            snp.Clean();
        }

    }
}
